package com.openwater.core;

import java.util.Vector;

public class Runner extends Thread {

    /** Runnable queue */
    private Vector<Runnable> queues;
    private boolean stop;
    /** when queues get over with work ,queueProcessedListener will be execute */
    private Runnable queueProcessedListener;
    private static Runner instance;
    private boolean paused;

    public Runner() {
        this.queues = new Vector<Runnable>();
        start();
    }

    public Runner(boolean paused) {
        this.queues = new Vector<Runnable>();
        this.paused = paused;
        start();
    }

    public synchronized void pause() {
        paused = true;
    }

    public synchronized void unpause() {
        paused = false;
        notifyAll();
    }

    public static Runner getInstance() {
        if (instance == null) {
            instance = new Runner();
        }
        return instance;
    }

    public void setQueueListener(Runnable r) {
        queueProcessedListener = r;
    }

    @Override
    public void run() {
        boolean events;
        while (!stop) {
            synchronized (this) {
                while (paused) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            events = false;
            while (!queues.isEmpty()) {
                events = true;
                Runnable running = queues.firstElement();
                queues.removeElementAt(0);
                try {
                    if (running instanceof Thread) {
                        Thread thread = (Thread) running;
                        if (!thread.isAlive()) {
                            thread.start();
                        }
                    } else {
                        ((Runnable) running).run();
                    }
                } catch (Throwable t) {
                    t.printStackTrace();
                }
                if (paused) {
                    break;
                }
            }
            if (events && queueProcessedListener != null) {
                queueProcessedListener.run();
            }
            synchronized (this) {
                if (!queues.isEmpty()) {
                    continue;
                }
                if (stop) {
                    return;
                }
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized void wait(Runnable runnable) {
        queues.addElement(runnable);
        try {
            runnable.wait();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    public synchronized void execute(Runnable runnable) {
        queues.addElement(runnable);
        notifyAll();
    }

    public synchronized void execute(Runnable[] runnable) {
        for (int i = 0; i < runnable.length; i++)
            queues.addElement(runnable[i]);
        notifyAll();
    }

    public synchronized void kill() {
        stop = true;
        notifyAll();
    }

}
